﻿using System;
using GeoAPI.Geometries;

namespace YJKGridTopologyCal.Geometries.Implementation
{
	public abstract class PackedCoordinateSequence : ICoordinateSequence, ICloneable
	{
		private static Ordinates DimensionToOrdinate(int dimension)
		{
			switch (dimension)
			{
			case 2:
				return Ordinates.XY;
			case 3:
				return Ordinates.XYZ;
			case 4:
				return Ordinates.XYZM;
			default:
			{
				Ordinates ordinates = Ordinates.None;
				for (int i = 3; i < dimension; i++)
				{
					ordinates |= (Ordinates)(1 << i);
				}
				return Ordinates.XY | ordinates;
			}
			}
		}

		public int Dimension
		{
			get
			{
				return this._dimension;
			}
			protected set
			{
				this._dimension = value;
				this._ordinates = PackedCoordinateSequence.DimensionToOrdinate(this._dimension);
			}
		}

		public Ordinates Ordinates
		{
			get
			{
				return this._ordinates;
			}
		}

		public abstract int Count { get; }

		public Coordinate GetCoordinate(int i)
		{
			Coordinate[] cachedCoords = this.GetCachedCoords();
			if (cachedCoords != null)
			{
				return cachedCoords[i];
			}
			return this.GetCoordinateInternal(i);
		}

		public Coordinate GetCoordinateCopy(int i)
		{
			return this.GetCoordinateInternal(i);
		}

		public void GetCoordinate(int i, Coordinate c)
		{
			c.X = this.GetOrdinate(i, Ordinate.X);
			c.Y = this.GetOrdinate(i, Ordinate.Y);
		}

		public Coordinate[] ToCoordinateArray()
		{
			Coordinate[] array = this.GetCachedCoords();
			if (array != null)
			{
				return array;
			}
			array = new Coordinate[this.Count];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = this.GetCoordinateInternal(i);
			}
			this.CoordRef = new WeakReference(array);
			return array;
		}

		private Coordinate[] GetCachedCoords()
		{
			if (this.CoordRef == null)
			{
				return null;
			}
			Coordinate[] array = (Coordinate[])this.CoordRef.Target;
			if (array != null)
			{
				return array;
			}
			this.CoordRef = null;
			return null;
		}

		public double GetX(int index)
		{
			return this.GetOrdinate(index, Ordinate.X);
		}

		public double GetY(int index)
		{
			return this.GetOrdinate(index, Ordinate.Y);
		}

		public abstract double GetOrdinate(int index, Ordinate ordinate);

		public void SetX(int index, double value)
		{
			this.CoordRef = null;
			this.SetOrdinate(index, Ordinate.X, value);
		}

		public void SetY(int index, double value)
		{
			this.CoordRef = null;
			this.SetOrdinate(index, Ordinate.Y, value);
		}

		public abstract void SetOrdinate(int index, Ordinate ordinate, double value);

		public override string ToString()
		{
			return CoordinateSequences.ToString(this);
		}

		protected abstract Coordinate GetCoordinateInternal(int index);

		public abstract object Clone();

		public abstract Envelope ExpandEnvelope(Envelope env);

		public abstract ICoordinateSequence Reversed();

		protected WeakReference CoordRef;

		private int _dimension;

		private Ordinates _ordinates;
	}
}
